/**
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 *         
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. Unless required by applicable law or
 * agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 */
package org.rhok.pdx.ncn.communicator;

import java.io.DataInputStream;
import java.net.URI;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.rhok.pdx.ncn.datatypes.LocationData;

import android.util.Log;

/**
 * Web client for connecting to the remove server.
 * @author pfritzsche
 */
public class WebClient {
	private static final String
		SERVER_URL = "http://cellstrength.herokuapp.com/",
		TAG = "WebClient",
		MEASUREMENTS = "measurements",
		LOCATION = "location",
		TIMESTAMP = "timestamp",
		LAT = "lat",
		LNG = "lng",
		SIGNAL = "signal",
		WIFI = "wifi",
		CONTENT_TYPE = "Content-type",
		URL_ENCODED = "application/x-www-form-urlencoded",
		FAKE_REQUEST_QUERY_STRING = "&range=100&lat=37.417006&lng=-122.089095&timestamp=";
	
	private static final double RANGE = 1;
	private static final int
		MAX_COUNT = 10,
		TIMEOUT = 30000;
	private static final long
        ONE_DAY = TimeUnit.DAYS.toMillis(730);
	
	/**
	 * Retrieves all data points from the server near the current location, starting at the time
	 * specified. TODO(pfritzsc): refactor to make method shorter.
	 * @param startTime the earliest time to ask for data
	 * @return LinkedList<LocationData> containing all responses from server
	 * @throws Exception thrown when there are server I/O issues or JSON formation issues
	 */
	public List<LocationData> getServerData(LocationData mostRecentData) throws Exception {
		DefaultHttpClient client = new DefaultHttpClient();
		HttpParams params = client.getParams();
		HttpConnectionParams.setConnectionTimeout(params, TIMEOUT);
		HttpConnectionParams.setSoTimeout(params, TIMEOUT);
		ConnManagerParams.setTimeout(params, TIMEOUT);
		
		StringBuilder sb = new StringBuilder();
		sb.append(SERVER_URL).append("?max_count=").append(MAX_COUNT);
		
		if (mostRecentData == null) {
		    sb.append(FAKE_REQUEST_QUERY_STRING).append(System.currentTimeMillis() - ONE_DAY);
		} else {
		    sb.append("&range=").append(RANGE)
		        .append("&lat=").append(Double.toString(mostRecentData.lat()))
		        .append("&lng=").append(Double.toString(mostRecentData.lng()))
		        .append("&timestamp=").append(mostRecentData.timestamp());
		}
		
		HttpGet request = new HttpGet();
		request.addHeader(CONTENT_TYPE, URL_ENCODED);
		request.setURI(new URI(sb.toString()));
		Log.d(TAG, "Requesting data from server: " + sb.toString());
		
		HttpResponse httpResponse = client.execute(request);
		int status = httpResponse.getStatusLine().getStatusCode();

		List<LocationData> results = null;
		if (status == HttpStatus.SC_OK) {
		    results = new LinkedList<LocationData>();
			DataInputStream dis = new DataInputStream(httpResponse.getEntity().getContent());
			JSONObject jsonResult = (JSONObject) new JSONTokener(dis.readLine()).nextValue();
			if (jsonResult.has(MEASUREMENTS)) {
				JSONArray objects = jsonResult.getJSONArray(MEASUREMENTS);
				for (int i = 0; i < objects.length(); i++) {
					JSONObject o = objects.getJSONObject(i);
					JSONObject loc = o.getJSONObject(LOCATION);
					results.add(new LocationData(
							o.getLong(TIMESTAMP), loc.getDouble(LAT), loc.getDouble(LNG),
							o.getInt(SIGNAL), o.getInt(WIFI)));
				}
			}
		}
		return results;
	}
}